%include "common.inc"

SECTION MBR vstart=0x7c00   ; 等价org 0x7c00
;AX——accumulator，累加寄存器
;CX——counter，计数寄存器
;DX——data，数据寄存器
;BX——base，基址寄存器
;SP——stack pointer，栈指针寄存器
;BP——base pointer，基址指针寄存器
;SI——source index，源变址寄存器
;DI——destination index，目的变址寄存器
;初始化寄存器
    mov ax, cs
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov fs, ax
    mov sp, 0x7c00
    mov ax, 0xb800
    mov gs, ax
;===通过BIOS中断服务程序INT 10h实现屏幕信息显示相关操作。INT 10h中断服务程序要求在调用时，必须向AH寄存器传入服务程序的主功能编号，再向其他寄存器传入参数。
; 清屏 利用0x06号功能，上卷全部行，则可清屏。
; -----------------------------------------------------------
;INT 0x10   功能号:0x06	   功能描述:上卷窗口
;------------------------------------------------------
;输入：
;AH 功能号= 0x06
;AL = 上卷的行数(如果为0,表示全部)
;BH = 上卷行属性
;(CL,CH) = 窗口左上角的(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;无返回值：
    mov ax, 0600h
    mov bx, 0700h
    mov cx, 0
    mov dx, 0184fh
    int 10h
    ;=== 显示文字：HelloWorld
    mov byte [gs:0x00],'H'
    mov byte [gs:0x01],0xA4

    mov byte [gs:0x02],'e'
    mov byte [gs:0x03],0xA4

    mov byte [gs:0x04],'l'
    mov byte [gs:0x05],0xA4

    mov byte [gs:0x06],'l'
    mov byte [gs:0x07],0xA4

    mov byte [gs:0x08],'o'
    mov byte [gs:0x09],0xA4

    mov byte [gs:0x0A],'W'
    mov byte [gs:0x0B],0xA4

    mov byte [gs:0x0C],'o'
    mov byte [gs:0x0D],0xA4

    mov byte [gs:0x0E],'r'
    mov byte [gs:0x0F],0xA4

    mov byte [gs:0x10],'l'
    mov byte [gs:0x11],0xA4

    mov byte [gs:0x12],'d'
    mov byte [gs:0x13],0xA4

;;;;;;;;;      打字字符串结束	 ;;;;;;;;;;;;;;;
    mov eax, LOADER_START_SECTOR ; 其实扇区lba的地址
    mov bx, LOADER_BASE_ADDR ; 写入地址
    mov cx, 4  ; 待读入的扇区数
    call rd_disk_m_16   ; 以下读取程序的的起始部分（一个扇区）

    jmp LOADER_BASE_ADDR + 0x300		

; 功能： 读取硬盘的n个扇区
rd_disk_m_16:
;--------------------------------
        ;eax=LBA扇区号
        ; bx=将数据写入的内存地址
        ; cx=读入的扇区数
    mov esi, eax ;备份eax
    mov di,cx    ; 备份cx

; 读写硬盘
; 第一步：设置要读取的扇区数
    mov dx,0x1f2
    mov al,cl
    out dx,al            ;读取的扇区数

    mov eax,esi	   ;恢复ax

;第2步：将LBA地址存入0x1f3 ~ 0x1f6
    ;LBA地址7~0位写入端口0x1f3
    mov dx,0x1f3                       
    out dx,al

    ;LBA地址15~8位写入端口0x1f4 
    mov cl,8
    shr eax,cl
    mov dx,0x1f4
    out dx,al

    ;LBA地址23~16位写入端口0x1f5
    shr eax,cl
    mov dx,0x1f5
    out dx,al
    
    shr eax,cl
    and al,0x0f	   ;lba第24~27位
    or al,0xe0	   ; 设置7～4位为1110,表示lba模式
    mov dx,0x1f6
    out dx,al

;第3步：向0x1f7端口写入读命令，0x20 
    mov dx,0x1f7
    mov al,0x20                        
    out dx,al

;第4步：检测硬盘状态
.not_ready:
    ;同一端口，写时表示写入命令字，读时表示读入硬盘状态
    nop
    in al,dx
    and al,0x88	   ;第4位为1表示硬盘控制器已准备好数据传输，第7位为1表示硬盘忙
    cmp al,0x08
    jnz .not_ready	   ;若未准备好，继续等。

;第5步：从0x1f0端口读数据
    mov ax, di
    mov dx, 256
    mul dx
    mov cx, ax	   ; di为要读取的扇区数，一个扇区有512字节，每次读入一个字，
                    ; 共需di*512/2次，所以di*256
    mov dx, 0x1f0
.go_on_read:
    in ax,dx
    mov [bx],ax
    add bx,2		  
    loop .go_on_read
    ret

    times 510-($-$$) db 0
    db 0x55,0xaa